package com.cm.projectx.job.utils;

import com.cm.projectx.entity.PriceTask;
import com.cm.projectx.job.entity.JobParamEntity;
import lombok.extern.slf4j.Slf4j;

import java.util.*;

@Slf4j
public class JobParamConvert {

    public static JobParamEntity convertByTaskScheduleType(PriceTask task) {
        JobParamEntity jobParamEntity = new JobParamEntity();
        jobParamEntity.setJobClassName("com.cm.projectx.job.worker.HandlerPushPriceTaskWorker");
        jobParamEntity.setJobName(task.getTaskName() + ":" + task.getTaskCode());
        jobParamEntity.setJobGroup("周期定时任务");
        jobParamEntity.setTriggerName(task.getTaskName() + "Trigger");
        jobParamEntity.setTriggerGroup(task.getTaskName() + "TriggerGroup");
        jobParamEntity.setScheduleTaskStartTime(task.getScheduleTaskStartTime());
        jobParamEntity.setScheduleTaskEndTime(task.getScheduleTaskEndTime());
        switch (task.getScheduleType()) {
            case "旬报":
                try {
                    // 获取用户选择的日期，用逗号分隔（如 "5,10,15"）
                    String tenDayValue = task.getTenDay();

                    // 检查是否包含逗号（表示多选）
                    if (tenDayValue.contains(",")) {
                        // 分割字符串
                        String[] days = tenDayValue.split(",");

                        // 验证并构建日期的字符串
                        StringBuilder dayBuilder = new StringBuilder();
                        for (int i = 0; i < days.length; i++) {
                            try {
                                int day = Integer.parseInt(days[i].trim());
                                // 验证日期是否在允许的范围内 (5,10,15,25)
                                if (day != 5 && day != 10 && day != 15 && day != 25) {
                                    throw new IllegalArgumentException("旬报日期只能是5、10、15、25号");
                                }

                                if (i > 0) {
                                    dayBuilder.append(",");
                                }
                                dayBuilder.append(day);
                            } catch (NumberFormatException e) {
                                throw new IllegalArgumentException("旬报日期必须是有效数字");
                            }
                        }
                        jobParamEntity.setCronExpression("0 0 0 " + dayBuilder + " * ?");
                    } else {
                        // 如果是单个值，验证并处理
                        try {
                            int day = Integer.parseInt(tenDayValue.trim());
                            // 验证单个日期是否在允许的范围内
                            if (day != 5 && day != 10 && day != 15 && day != 25) {
                                throw new IllegalArgumentException("旬报日期只能是5、10、15、25号");
                            }
                            jobParamEntity.setCronExpression("0 0 0 " + day + " * ?");
                        } catch (NumberFormatException e) {
                            throw new IllegalArgumentException("旬报日期必须是有效数字");
                        }
                    }
                } catch (Exception e) {
                    throw new IllegalArgumentException("旬报日期配置错误: " + e.getMessage());
                }
                break;
            case "月报":
                jobParamEntity.setCronExpression("0 0 0 " + task.getDay() + " * ?");
                break;
            case "周报":
                // 处理英文缩写形式的多选周情况
                String weekDayValue = task.getWeekDay();
                // 检查是否包含逗号（表示多选）
                if (weekDayValue.contains(",")) {
                    // 分割字符串
                    String[] days = weekDayValue.split(",");

                    // 验证并构建周几的英文缩写字符串
                    StringBuilder weekDaysBuilder = new StringBuilder();
                    for (int i = 0; i < days.length; i++) {
                        String dayAbbreviation = days[i].trim().toUpperCase();

                        // 验证周几的英文缩写是否有效
                        if (!isValidDayAbbreviation(dayAbbreviation)) {
                            throw new IllegalArgumentException("无效的星期缩写: " + dayAbbreviation + "，有效值为: SUN, MON, TUE, WED, THU, FRI, SAT");
                        }

                        if (i > 0) {
                            weekDaysBuilder.append(",");
                        }
                        weekDaysBuilder.append(dayAbbreviation);
                    }
                    jobParamEntity.setCronExpression("0 0 0 ? * " + weekDaysBuilder);
                } else {
                    // 如果是单个值，验证英文缩写
                    String dayAbbreviation = weekDayValue.trim().toUpperCase();
                    if (!isValidDayAbbreviation(dayAbbreviation)) {
                        throw new IllegalArgumentException("无效的星期缩写: " + dayAbbreviation + "，有效值为: SUN, MON, TUE, WED, THU, FRI, SAT");
                    }
                    jobParamEntity.setCronExpression("0 0 0 ? * " + dayAbbreviation);
                }
                break;
            case "自定义":
                // 获取自定义的cron表达式
                String customizeCron = task.getCustomizeCron();
                if (customizeCron == null || customizeCron.trim().isEmpty()) {
                    log.warn("自定义cron表达式为空，使用默认处理");
                    jobParamEntity.setCronExpression(customizeCron);
                    break;
                }

                // 解析提前下发天数
                Integer advanceDays = parseAdvanceDays(task.getAdvanceDays());

                // 如果设置了有效的提前下发天数（1-5天）
                if (advanceDays != null) {
                    try {
                        String adjustedCron = adjustComplexCronExpression(customizeCron, advanceDays);
                        jobParamEntity.setCronExpression(adjustedCron);
                    } catch (Exception e) {
                        log.error("处理自定义任务cron表达式异常，使用原表达式: {}", customizeCron, e);
                        jobParamEntity.setCronExpression(customizeCron);
                    }
                } else {
                    // 没有设置提前天数或不在有效范围内，使用原表达式
                    jobParamEntity.setCronExpression(customizeCron);
                }
                break;
        }
        return jobParamEntity;
    }
    /**
     * 解析提前下发天数
     */
    private static Integer parseAdvanceDays(String advanceDaysStr) {
        if (advanceDaysStr == null || advanceDaysStr.trim().isEmpty()) {
            return null;
        }

        try {
            int days = Integer.parseInt(advanceDaysStr.trim());
            if (days >= 1 && days <= 5) {
                return days;
            } else {
                log.warn("提前下发天数超出范围(1-5): {}, 将使用原表达式", days);
                return null;
            }
        } catch (NumberFormatException e) {
            log.warn("提前下发天数格式错误: {}, 将使用原表达式", advanceDaysStr);
            return null;
        }
    }

    /**
     * 调整复杂的cron表达式（支持日、月、年字段中的多个值）
     */
    private static String adjustComplexCronExpression(String originalCron, int advanceDays) {
        String[] cronParts = originalCron.split(" ");
        if (cronParts.length < 6) {
            log.warn("cron表达式格式不正确，使用原表达式: {}", originalCron);
            return originalCron;
        }
//        String secondField = cronParts[0];
//        String minuteField = cronParts[1];
//        String hourField = cronParts[2];
        String dayField = cronParts[3];   // 日字段 (1-31)
        String monthField = cronParts[4]; // 月字段 (1-12 or JAN-DEC)
        String dayOfWeekField = cronParts[5]; // 周字段
        String yearField = cronParts.length > 6 ? cronParts[6] : "*"; // 年字段 (可选)

        // 解析所有字段
        List<Integer> days = parseCronField(dayField, 1, 31);
        List<Integer> months = parseCronField(monthField, 1, 12);
        List<Integer> years = parseCronField(yearField, 1970, 2099);

        if (days.isEmpty() || months.isEmpty() || years.isEmpty()) {
            log.warn("无法解析cron表达式字段，使用原表达式: {}", originalCron);
            return originalCron;
        }

        // 计算所有可能的日期组合
        Set<AdjustedDate> adjustedDates = calculateAdjustedDates(days, months, years, advanceDays);

        // 构建新的cron字段
        String adjustedDayField = buildCronFieldFromDates(adjustedDates, DatePart.DAY);
        String adjustedMonthField = buildCronFieldFromDates(adjustedDates, DatePart.MONTH);
        String adjustedYearField = buildCronFieldFromDates(adjustedDates, DatePart.YEAR);

        // 构建新的cron表达式
        String newCron = String.format("0 0 0 %s %s %s %s",
                adjustedDayField, adjustedMonthField, dayOfWeekField, adjustedYearField).trim();

        log.info("自定义任务提前下发：原表达式[{}]提前{}天，调整为[{}]",
                originalCron, advanceDays, newCron);

        return newCron;
    }

    /**
     * 解析cron字段中的多个值
     */
    private static List<Integer> parseCronField(String field, int minValue, int maxValue) {
        List<Integer> values = new ArrayList<>();

        if (field == null || field.trim().isEmpty()) {
            return values;
        }

        // 处理特殊值
        if ("*".equals(field) || "?".equals(field)) {
            // 对于通配符，我们生成范围内的所有值
            for (int i = minValue; i <= maxValue; i++) {
                values.add(i);
            }
            return values;
        }

        // 处理逗号分隔的值
        if (field.contains(",")) {
            String[] parts = field.split(",");
            for (String part : parts) {
                try {
                    int value = parseCronValue(part.trim(), minValue, maxValue);
                    if (value >= minValue && value <= maxValue) {
                        values.add(value);
                    }
                } catch (NumberFormatException e) {
                    log.warn("无法解析cron字段值: {}", part);
                }
            }
            return values;
        }

        // 处理单个值
        try {
            int value = parseCronValue(field, minValue, maxValue);
            if (value >= minValue && value <= maxValue) {
                values.add(value);
            }
        } catch (NumberFormatException e) {
            log.warn("无法解析cron字段值: {}", field);
        }

        return values;
    }

    /**
     * 解析单个cron值（支持月份缩写）
     */
    private static int parseCronValue(String value, int minValue, int maxValue) {
        // 处理月份缩写
        if (minValue == 1 && maxValue == 12) {
            String[] monthAbbr = {"JAN", "FEB", "MAR", "APR", "MAY", "JUN",
                    "JUL", "AUG", "SEP", "OCT", "NOV", "DEC"};
            for (int i = 0; i < monthAbbr.length; i++) {
                if (monthAbbr[i].equalsIgnoreCase(value)) {
                    return i + 1;
                }
            }
        }

        // 处理数字
        return Integer.parseInt(value);
    }

    /**
     * 日期部分枚举
     */
    private enum DatePart {
        DAY, MONTH, YEAR
    }

    /**
     * 调整后的日期类
     */
    private static class AdjustedDate {
        final int day;
        final int month;
        final int year;

        AdjustedDate(int day, int month, int year) {
            this.day = day;
            this.month = month;
            this.year = year;
        }

        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;
            AdjustedDate that = (AdjustedDate) o;
            return day == that.day && month == that.month && year == that.year;
        }

        @Override
        public int hashCode() {
            return Objects.hash(day, month, year);
        }
    }

    /**
     * 计算所有调整后的日期
     */
    private static Set<AdjustedDate> calculateAdjustedDates(List<Integer> days, List<Integer> months,
                                                     List<Integer> years, int advanceDays) {
        Set<AdjustedDate> adjustedDates = new HashSet<>();

        for (int year : years) {
            for (int month : months) {
                for (int day : days) {
                    AdjustedDate adjustedDate = calculateAdjustedDate(day, month, year, advanceDays);
                    if (adjustedDate != null) {
                        adjustedDates.add(adjustedDate);
                    }
                }
            }
        }

        return adjustedDates;
    }

    /**
     * 计算单个日期的调整
     */
    private static AdjustedDate calculateAdjustedDate(int day, int month, int year, int advanceDays) {
        try {
            // 创建日历实例
            Calendar calendar = Calendar.getInstance();
            calendar.set(year, month - 1, day); // Calendar月份是0-11

            // 减去提前天数
            calendar.add(Calendar.DAY_OF_MONTH, -advanceDays);

            // 获取调整后的日期
            int adjustedYear = calendar.get(Calendar.YEAR);
            int adjustedMonth = calendar.get(Calendar.MONTH) + 1; // 转回1-12
            int adjustedDay = calendar.get(Calendar.DAY_OF_MONTH);

            return new AdjustedDate(adjustedDay, adjustedMonth, adjustedYear);
        } catch (Exception e) {
            log.warn("日期计算失败: {}-{}-{}, 提前{}天", year, month, day, advanceDays, e);
            return null;
        }
    }

    /**
     * 从调整后的日期集合构建cron字段
     */
    private static String buildCronFieldFromDates(Set<AdjustedDate> dates, DatePart part) {
        Set<Integer> values = new TreeSet<>();

        for (AdjustedDate date : dates) {
            switch (part) {
                case DAY:
                    values.add(date.day);
                    break;
                case MONTH:
                    values.add(date.month);
                    break;
                case YEAR:
                    values.add(date.year);
                    break;
            }
        }

        if (values.isEmpty()) {
            return "*";
        }

        // 如果值连续，可以优化为范围表示
        if (values.size() > 1 && isConsecutive(values)) {
            int min = values.iterator().next();
            int max = ((TreeSet<Integer>) values).last();
            return min + "-" + max;
        }

        // 否则使用逗号分隔
        List<String> valueStrs = new ArrayList<>();
        for (int value : values) {
            valueStrs.add(String.valueOf(value));
        }
        return String.join(",", valueStrs);
    }

    /**
     * 检查值是否连续
     */
    private static boolean isConsecutive(Set<Integer> values) {
        if (values.isEmpty()) {
            return false;
        }

        Iterator<Integer> it = values.iterator();
        int prev = it.next();
        while (it.hasNext()) {
            int current = it.next();
            if (current != prev + 1) {
                return false;
            }
            prev = current;
        }
        return true;
    }
    /**
     * 验证星期英文缩写是否有效
     * @param abbreviation 英文缩写
     * @return 是否有效
     */
    private static boolean isValidDayAbbreviation(String abbreviation) {
        return abbreviation.matches("^(SUN|MON|TUE|WED|THU|FRI|SAT)$");
    }
}
